package org.xmap.util;

import java.io.IOException;
import java.io.InputStream;

/**
 * <p>编码转换器，实现UTF-8、Unicode编码文件的读取以及UTF-8到Unicode的编码转换。</p>
 * @author Zealot
 * @version 1.0
 */
public final class CodeConverter {

    /**
     * Unicode字符和字节数组的转换
     * @param abyte0
     * @param i
     * @return
     */
    public static String byteArrayToString(byte abyte0[], int i) {
        StringBuffer stringbuffer = new StringBuffer("");
        for (int j = 0; j < i;) {
            int k = abyte0[j++]; //注意在这个地方进行了码制的转换
            if (k < 0) {
                k += 256;
            }
            int l = abyte0[j++];
            if (l < 0) {
                l += 256;
            }
            char c = (char) (k + (l << 8));//把高位和低位数组装起来
            stringbuffer.append(c);
        }

        return stringbuffer.toString();
    }

    public static String byteArrayToString(byte abyte0[]) {
        return byteArrayToString(abyte0, abyte0.length);
    }

    public static byte[] stringToByteArray(String s) {
        int i = s.length();
        byte abyte0[] = new byte[i << 1];
        int j = 0;
        for (int k = 0; k < i; k++) {
            char c = s.charAt(k);
            abyte0[j++] = (byte) (c & 0xff); //每一个位按位转化
            abyte0[j++] = (byte) (c >> 8);
        }

        return abyte0;
    }
    /**
     * 读取文本文件时所使用的字节缓冲区大小
     */
    public static final int BUFFER_SIZE = 1024;

    /**
     * 读取Unicode编码文本文件
     * @param resource String - 文件名
     * @return String - Unicode文本
     */
    public static String readUcsBigEndian(String resource) {
        byte data[] = new byte[BUFFER_SIZE];
        String result = null;
        InputStream is = null;
        try {
            is = resource.getClass().getResourceAsStream(resource);
            is.skip(2); // 跳过两个字节的文件头
            is.read(data);
            StringBuffer sb = new StringBuffer("");
            for (int j = 0; j < data.length;) {
                int l = data[j++];
                int h = data[j++];
                char c = (char) ((l & 0xff) | ((h << 8) & 0xff00));
                sb.append(c);
            }
            result = sb.toString();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * 读取UTF-8编码文本文件
     * @param resource String - 文件名
     * @return String - UTF-8文本
     */
    public static String readUtf8(String resource) {
        byte data[] = new byte[BUFFER_SIZE];
        String result = null;
        InputStream is = null;
        try {
            is = resource.getClass().getResourceAsStream(resource);
            is.read(data);
            result = new String(data, "UTF-8");
        } catch (IOException ex) {
            System.out.println(ex);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * 读取UTF-8编码文本文件并转化为Unicode编码字符串返回
     * @param resource String - 文件名
     * @return String - Unicode编码字符串
     */
    public static String read_UTF2Uni(String resource) {
        byte data[] = new byte[BUFFER_SIZE];
        String result = null;
        InputStream is = null;
        try {
            is = resource.getClass().getResourceAsStream(resource);
            int len = is.read(data);
            result = UTF2Uni(data, len);
        } catch (IOException ex) {
            System.out.println(ex);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * 将UTF-8字节数据转化为Unicode字符串
     * @param utf_data byte[] - UTF-8编码字节数组
     * @param len int - 字节数组长度
     * @return String - 变换后的Unicode编码字符串
     */
    public static String UTF2Uni(byte[] utf_data, int len) {
        StringBuffer unis = new StringBuffer();
        char unic = 0;
        int ptr = 0;
        int cntBits = 0;
        for (; ptr < len;) {
            cntBits = getCntBits(utf_data[ptr]);
            if (cntBits == -1) {
                ++ptr;
                continue;
            } else if (cntBits == 0) {
                unic = UTFC2UniC(utf_data, ptr, cntBits);
                ++ptr;
            } else {
                unic = UTFC2UniC(utf_data, ptr, cntBits);
                ptr += cntBits;
            }
            unis.append(unic);
        }
        return unis.toString();
    }

    /**
     * 将指定的UTF-8字节组合成一个Unicode编码字符
     * @param utf byte[] - UTF-8字节数组
     * @param sptr int - 编码字节起始位置
     * @param cntBits int - 编码字节数
     * @return char - 变换后的Unicode字符
     */
    private static char UTFC2UniC(byte[] utf, int sptr, int cntBits) {
        /*
        Unicode <-> UTF-8
        U-00000000 - U-0000007F:  0xxxxxxx
        U-00000080 - U-000007FF:  110xxxxx 10xxxxxx
        U-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx
        U-00010000 - U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
        U-00200000 - U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
        U-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
         */
        int uniC = 0; //  represent the unicode char
        byte firstByte = utf[sptr];
        int ptr = 0; //  pointer 0 ~ 15
        // resolve single byte UTF-8 encoding char
        if (cntBits == 0) {
            return (char) firstByte;
        }
        // resolve the first byte
        firstByte &= (1 << (7 - cntBits)) - 1;
        // resolve multiple bytes UTF-8 encoding char(except the first byte)
        for (int i = sptr + cntBits - 1; i > sptr; --i) {
            byte utfb = utf[i];
            uniC |= (utfb & 0x3f) << ptr;
            ptr += 6;
        }
        uniC |= firstByte << ptr;
        return (char) uniC;
    }
    // 根据给定字节计算UTF-8编码的一个字符所占字节数
    // UTF-8规则定义，编码字节数只能是0或2~6

    private static int getCntBits(byte b) {
        int cnt = 0;
        if (b == 0) {
            return -1;
        }
        for (int i = 7; i >= 0; --i) {
            if (((b >> i) & 0x1) == 1) {
                ++cnt;
            } else {
                break;
            }
        }
        return (cnt > 6 || cnt == 1) ? -1 : cnt;
    }
}
